﻿using System;
using System.Collections.Generic;
using System.Data.Entity.Core.Mapping;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Diagnostics;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.SessionState;
using Common;
using Controllers.Controllers;
using Model.DbContext;
using QScheduler;

namespace UI
{
    // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明，
    // 请访问 http://go.microsoft.com/?LinkId=9394801

    //在 Global.asax 被更改后ASP.NET 页面框架会重新启动应用程序，包括关闭所有的浏览器会话，去除所有状态信息，并重新启动应用程序域。  
    public class MvcApplication : System.Web.HttpApplication// SpringMvcApplication  //System.Web.HttpApplication 这边实现SpringMvcApplication来使得Spring的Ioc可以从Controller自动属性注入，不需要手动（也可以不用SpringMvcApplication，直接在基类里手动一次注入，不过这样灵活性不高）
    {
        protected void Application_Start()
        {
            //初始化视图引擎为Razor视图引擎
            //规定了系统只能采用Razor视图引擎，省去了判断选择视图引擎的过程，属于视图引擎的优化
            ViewEngines.Engines.Clear();
            ViewEngines.Engines.Add(new RazorViewEngine());

            AreaRegistration.RegisterAllAreas();
            HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Disabled); //全局禁用session

            WebApiConfig.Register(GlobalConfiguration.Configuration);//禁webapi,dll暂时没有引用，外加没有api的功能
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); //注册全局过滤器（对每次请求进行过滤）
            RouteConfig.RegisterRoutes(RouteTable.Routes); //注册路由规则
            IocConfig.BuildMvcContainer();//Ioc注入

            //调度程序
            QuartzBll.Start();
            //FluentBll.Start();

            #region EF初始化优化

            ////EF默认的数据库初始化器(四种初始化方式，只有禁用初始化器这种方式比较靠谱)
            System.Data.Entity.Database.SetInitializer<ModelContainer>(null);
            ////EF Migration作为数据库初始化器（发布部署应用程序的时候，当程序启动的时候它自动更新数据库，DbContext 第一次被使用的时候执行）
            //Database.SetInitializer(new MigrateDatabaseToLatestVersion<DbContext1, Configuration>());

            //首次使用EF的DbContext，内存中生成mapping views(耗时操作)
            ModelContainer dbContext = new ModelContainer();
            var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
            var mappingCollection = (StorageMappingItemCollection)objectContext.MetadataWorkspace.GetItemCollection(DataSpace.CSSpace);
            mappingCollection.GenerateViews(new List<EdmSchemaError>());

            #endregion

            LogHelper.Debug("*********************************Application_Start执行完毕****************************************");
        }

        protected void Application_End()
        {
            QuartzBll.Stop();
            //FluentBll.Stop();
        }

    /// <summary>
        /// 顶层统一异常日志处理和异常页面反馈(这是异常的最顶层控制,能处理500以外的错误，开发版使用，帮助找错)
        /// </summary>
        protected void Application_Error(object sender, EventArgs e)
        {
            Exception ex = HttpContext.Current.Server.GetLastError();
            HttpContext httpContext = ((MvcApplication)sender).Context;
            RouteData currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));
            ErrorController errorController = new ErrorController();
            RouteData jumpRouteData = new RouteData();
            string currentController = "";
            string currentAction = "";
            string jumpAction = "Error";

            #region 跳转异常页前先记录异常

            Type exceptionType = typeof(Exception);
            if (ex.GetType() == exceptionType)//异常可能被Throw new Exception(e.Message);处理过
            {
                LogHelper.Error("异常可能被程序捕获处理(*^__^*)");
            }
            else
            {
                LogHelper.Error("异常未被程序捕获处理(●￣(ｴ)￣●)");
            }

            #endregion

            #region 跳转异常页面

            if (!new HttpRequestWrapper(httpContext.Request).IsAjaxRequest()) //非ajax异步请求页面控制跳转，ajax请求直接由ajax的error方法输出异常
            {
                if (currentRouteData != null)
                {
                    if (currentRouteData.Values["controller"] != null && !string.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
                    {
                        currentController = currentRouteData.Values["controller"].ToString();
                    }
                    if (currentRouteData.Values["action"] != null && !string.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
                    {
                        currentAction = currentRouteData.Values["action"].ToString();
                    }
                }
                if (ex is HttpException)
                {
                    var httpEx = ex as HttpException;
                    switch (httpEx.GetHttpCode())
                    {
                        case 404://500以外错误
                            {
                                jumpAction = "Page404";
                                break;
                            }
                        default://500错误
                            {
                                jumpAction = "Error";
                                break;
                            }
                    }
                }
                httpContext.ClearError();
                httpContext.Response.Clear();
                httpContext.Response.StatusCode = ex is HttpException ? ((HttpException)ex).GetHttpCode() : 500;
                httpContext.Response.TrySkipIisCustomErrors = true;
                jumpRouteData.Values["controller"] = "Error";
                jumpRouteData.Values["action"] = jumpAction;
                if (jumpAction == "Page404")//如果访问的控制器不存在则会显示404页面源码，此处为修复此Bug单独处理404错误
                {
                    Response.Redirect("/Error/Page404");
                }
                else
                {
                    errorController.ViewData.Model = new HandleErrorInfo(ex, currentController, currentAction);//错误信息
                    ((IController)errorController).Execute(//请求转发
                        new RequestContext(
                            new HttpContextWrapper(httpContext), //类似于请求转发（始终是一次请求）
                            jumpRouteData)
                        );
                }
            }    

            #endregion

        }
    }
}